package snmp;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snmp4j.*;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.MessageProcessingModel;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.PDUFactory;
import org.snmp4j.util.TableEvent;
import org.snmp4j.util.TableUtils;

import java.io.IOException;
import java.util.List;
import java.util.Vector;

/**
 * </p>
 *
 * @author zhangsh
 * @version 1.0.0
 * @since 2019-05-18
 */
public class SnmpUtil {

    private static final Logger log = LoggerFactory.getLogger(SnmpUtil.class);

    /**
     * 默认读共同体名称
     */
    private static final String OCTET_STRING_DEFAULT_R = "public";
    /**
     * 默认读写共同体名称
     */
    private static final String OCTET_STRING_DEFAULT_RW = "private";


    public static void main(String[] args) {

        String[] oids = {"1.3.6.1.2.1.25.2.3.1.2",  //type 存储单元类型
                "1.3.6.1.2.1.25.2.3.1.3",  //descr
                "1.3.6.1.2.1.25.2.3.1.4",  //unit 存储单元大小
                "1.3.6.1.2.1.25.2.3.1.5",  //size 总存储单元数
                "1.3.6.1.2.1.25.2.3.1.6"}; //used 使用存储单元数;

        /*String[] oids = new String[]{"1.3.6.1.2.1.25.4.2.1.1",  //index
                "1.3.6.1.2.1.25.4.2.1.2",   //name
                "1.3.6.1.2.1.25.4.2.1.4",   //run path
                "1.3.6.1.2.1.25.4.2.1.6",   //type
                "1.3.6.1.2.1.25.5.1.1.1",   //cpu
                "1.3.6.1.2.1.25.5.1.1.2"};  //memory*/
//        sendSnmp("192.168.2.188", "1.3.6.1.2.1.1.5.0");
//        String result = getSnmpOnly("192.168.2.188", "1.3.6.1.2.1.1.5.0");
//localhost.localdomain
        boolean result = setSnmpOnly("192.168.2.188", "1.3.6.1.2.1.1.5.0", "localhost.localdomain");

        System.out.println("result : " + result);
    }

    /**
     * 获取单个MIB信息
     * @param targetIp
     * @param oidStr
     * @return
     */
    public static String getSnmpOnly(String targetIp, String oidStr){
        return getSnmpOnly(targetIp, OCTET_STRING_DEFAULT_R, oidStr);
    }

    public static boolean setSnmpOnly(String targetIp, String oidStr, String oidName){
        return setSnmpOnly(targetIp, OCTET_STRING_DEFAULT_RW, oidStr, oidName);
    }

    /**
     * 获取单个MIB信息
     * @param targetIp
     * @param oidStr
     * @return
     */
    public static String getSnmpOnly(String targetIp, String octetString, String oidStr){

        if(StringUtils.isBlank(targetIp) || StringUtils.isBlank(octetString) || StringUtils.isBlank(oidStr)){
            log.error("获取单个MIB时出错，原因：参数有误");
            return "";
        }

        TransportMapping transport = null;
        Snmp snmp = null;
        CommunityTarget target = null;

        try {
            // 设置协议以及创建Snmp对象
            transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);
            snmp.listen();

            // 设置target
            target = new CommunityTarget();
            // 设置共同体字符串
            target.setCommunity(new OctetString(octetString));
            // 协议版本
            target.setVersion(SnmpConstants.version2c);
            // 设置尝试次数
            target.setRetries(2);
            // 设置延时
            target.setTimeout(5*1000L);
            // 设置目标地址
            target.setAddress(GenericAddress.parse("udp:"+ targetIp + "/161"));

            // 构造PDU报文
            PDU request = new PDU();
            // 设置报文的类型
            request.setType(PDU.GET);
            // 设置单个oid
            OID oid = new OID(oidStr);
            // 绑定请求
            request.add(new VariableBinding(oid));

            // 设置响应
            ResponseEvent response = snmp.send(request, target);
            // 处理响应
            if(response == null || response.getResponse()==null){
                System.out.println("无响应");
                log.error("无响应");
                return "";
            }

            Vector<? extends VariableBinding> variableBindings = response.getResponse().getVariableBindings();
            if(variableBindings==null || variableBindings.isEmpty()){
                System.out.println("返回信息为空");
                log.error("返回信息为空出错");
                return "";
            }

            StringBuilder result = new StringBuilder(oidStr).append(" : ");
            for(VariableBinding bind : variableBindings){
                System.out.println(bind.toValueString());

                result.append(bind.toValueString());
            }

            return result.toString();

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            close(snmp);
            close(transport);
        }

        return "";
    }

    /**
     * 设置单个MIB信息
     * @param targetIp
     * @param octetString
     * @param oidStr
     * @param oidnName
     * @return
     */
    public static boolean setSnmpOnly(String targetIp, String octetString, String oidStr, String oidnName){


        TransportMapping transport = null;
        Snmp snmp = null;
        CommunityTarget target = null;

        try {
            // 设置snmp对象
            transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);
            snmp.listen();

            // 设置target
            target = new CommunityTarget();
            // 设置共同体字符串
            target.setCommunity(new OctetString(octetString));
            // 协议版本
            target.setVersion(SnmpConstants.version2c);
            // 设置尝试次数
            target.setRetries(2);
            // 设置延时
            target.setTimeout(5*1000L);
            // 设置目标地址
            target.setAddress(GenericAddress.parse("udp:"+ targetIp + "/161"));

            // 设置PDU
            PDU request = new PDU();
            request.setType(PDU.SET);
            OID oid = new OID(oidStr);
            OctetString name = new OctetString(oidnName);
            request.add(new VariableBinding(oid, name));

            // 设置response
            ResponseEvent response = snmp.send(request, target);
            // 处理响应
            if(response == null || response.getResponse()==null){
                log.error("响应出错");
                return false;
            }

            Vector<? extends VariableBinding> variableBindings = response.getResponse().getVariableBindings();
            if(variableBindings==null || variableBindings.isEmpty()){
                System.out.println("返回信息为空");
                log.error("返回信息为空出错");
                return false;
            }

            StringBuilder result = new StringBuilder(oidStr).append(" : ");
            for(VariableBinding bind : variableBindings){
                System.out.println(bind.toValueString());

                result.append(bind.toValueString());
            }

            return true;

        } catch (IOException e) {
            e.printStackTrace();
        }


        return false;

    }








    //获取内存相关信息
    public static void sendSnmp(String targetIp, String... oids) {

        TransportMapping transport = null;
        Snmp snmp = null;
        CommunityTarget target;

        try {
            transport = new DefaultUdpTransportMapping();
            snmp = new Snmp(transport);//创建snmp
            snmp.listen();//监听消息

            target = new CommunityTarget();
            target.setCommunity(new OctetString("public"));
            target.setRetries(2);
            target.setAddress(GenericAddress.parse("udp:"+targetIp+"/161"));
            target.setTimeout(8000);
            target.setVersion(SnmpConstants.version2c);
            TableUtils tableUtils = new TableUtils(snmp, new PDUFactory() {
                @Override
                public PDU createPDU(Target arg0) {
                    PDU request = new PDU();
                    request.setType(PDU.GET);
                    return request;
                }

                @Override
                public PDU createPDU(MessageProcessingModel messageProcessingModel) {

                    return null;
                }
            });
            OID[] columns = new OID[oids.length];
            for (int i = 0; i < oids.length; i++){
                columns[i] = new OID(oids[i]);
            }

            @SuppressWarnings("unchecked")
            List<TableEvent> list = tableUtils.getTable(target, columns, null, null);

            for (TableEvent event : list) {
                VariableBinding[] values = event.getColumns();
                if (values == null){
                    continue;
                }
                System.out.println("获取的结果");
                for(VariableBinding binding : values){
                    System.out.println(binding.toValueString());
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (transport != null){
                    transport.close();
                }

                if (snmp != null){
                    snmp.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static void close(Session snmp){
        if(snmp == null){
            return;
        }
        try {
            snmp.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void close(TransportMapping transportMapping){
        if(transportMapping == null){
            return;
        }
        try {
            transportMapping.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
